package com.voice.core.api.utils;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.TreeMap;

import com.voice.core.api.model.ApiHttpMessage;
import com.voice.core.api.model.ApiRequest;
import com.voice.core.api.model.ApiResponse;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.HmacAlgorithms;
import org.apache.commons.codec.digest.HmacUtils;
import org.springframework.util.StringUtils;

public class SignUtil {

    public static String sign(ApiRequest request, String secret) {
        String signString = buildStringToSign(request);
        return Base64.encodeBase64String(new HmacUtils(HmacAlgorithms.HMAC_SHA_256, secret).hmac(signString));
    }

    public static String buildStringToSign(ApiRequest apiRequest) {
        StringBuilder sb = new StringBuilder();
        sb.append(apiRequest.getMethod().getValue()).append("\n");
        if (apiRequest.getFirstHeaderValue("accept") != null) {
            sb.append(apiRequest.getFirstHeaderValue("accept"));
        }
        sb.append("\n");

        if (apiRequest.getFirstHeaderValue("content-md5") != null) {
            sb.append(apiRequest.getFirstHeaderValue("content-md5"));
        }
        sb.append("\n");

        if (apiRequest.getFirstHeaderValue("content-type") != null) {
            sb.append(apiRequest.getFirstHeaderValue("content-type"));
        }
        sb.append("\n");

        if (apiRequest.getFirstHeaderValue("date") != null) {
            sb.append(apiRequest.getFirstHeaderValue("date"));
        }
        sb.append("\n");
        sb.append(buildHeaders(apiRequest));
        sb.append(buildResource(apiRequest));
        return sb.toString();
    }

    public static String buildStringToSign(ApiResponse apiResponse) {
        StringBuilder sb = new StringBuilder();
        sb.append(apiResponse.getCode()).append("\n");
        String signatureHeaders = apiResponse.getFirstHeaderValue("x-ca-signature-headers");
        if (!StringUtils.isEmpty(signatureHeaders)) {
            signatureHeaders = signatureHeaders.toLowerCase();
            String[] signatureHeaderList = signatureHeaders.split(",");

            for (int i = 0; i < signatureHeaderList.length; ++i) {
                if (apiResponse.getFirstHeaderValue(signatureHeaderList[i]) != null) {
                    sb.append(apiResponse.getFirstHeaderValue(signatureHeaderList[i]));
                    sb.append("\n");
                }
            }
        }
        return sb.toString();
    }

    private static String buildResource(ApiRequest request) {
        StringBuilder result = new StringBuilder();
        result.append(request.getPath());
        TreeMap<String, String> parameter = new TreeMap();
        if (null != request.getQuerys() && request.getQuerys().size() > 0) {
            parameter.putAll(request.getQuerys());
        }
        if (null != request.getFormParams() && request.getFormParams().size() > 0) {
            parameter.putAll(request.getFormParams());
        }
        if (parameter.size() > 0) {
            result.append("?");
            result.append(HttpCommonUtil.buildSignParamString(parameter));
        }
        return result.toString();
    }

    private static String buildHeaders(ApiHttpMessage apiHttpMessage) {
        Map<String, String> headersToSign = new TreeMap();
        StringBuilder signHeadersStringBuilder = new StringBuilder();
        HttpCommonUtil.mapConsume(apiHttpMessage.getHeaders(), (isFirst, entry) -> {
            if (entry.getKey().startsWith("x-ca-")) {
                signHeadersStringBuilder.append(",");
                signHeadersStringBuilder.append(entry.getKey());
                headersToSign.put(entry.getKey(), apiHttpMessage.getFirstHeaderValue(entry.getKey()));
            }
        });
        signHeadersStringBuilder.deleteCharAt(0);
        apiHttpMessage.addHeader("x-ca-signature-headers", signHeadersStringBuilder.toString());
        StringBuilder result = new StringBuilder();
        HttpCommonUtil.mapConsume(headersToSign, (isFirst, entry) ->result.append(entry.getKey()).append(":").append(entry.getValue()).append("\n"));
        return result.toString();
    }

    public static String base64AndMD5(byte[] bytes) {
        if (bytes == null) {
            throw new IllegalArgumentException("bytes can not be null");
        } else {
            try {
                MessageDigest md = MessageDigest.getInstance("MD5");
                md.reset();
                md.update(bytes);
                byte[] md5Result = md.digest();
                String base64Result = Base64.encodeBase64String(md5Result);
                return base64Result.length() > 24 ? base64Result.substring(0, 23) : base64Result;
            } catch (NoSuchAlgorithmException var4) {
                throw new IllegalArgumentException("unknown algorithm MD5");
            }
        }
    }
}

